home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / DELPHI32 / GRAPHICS / TS32 / SPRITE.PAS < prev    next >
Pascal/Delphi Source File  |  1996-03-14  |  13KB  |  432 lines

  1. unit Sprite;
  2.  
  3. (*********************************************
  4. TSprite->TObject
  5.  
  6. The base class for all sprites.  Descendants of
  7. this class are managed by the TDIBDrawingSurface
  8. sprite engine.
  9.  
  10. Properties
  11.  
  12. BoundingRect-
  13.   The rectangle that bounds the sprite.  Determined based on
  14.   the sprite's Width and Height and Margin properties.
  15. Dead-
  16.   The sprite engine sets this to TRUE to flag that the sprite
  17.   should be removed from the list.
  18. Destination-
  19.   The sprite's logical destination.
  20. DIBDrawingSurface-
  21.   Returns the TDIBDrawingSurface that this sprite is
  22.   registered with.  This is set by a TSpriteEngine that the
  23.   sprite is added to.
  24. Dirty-
  25.   Flags whether this sprite needs to be redrawn when the
  26.   dirty rectangle system is employed.  Used by the sprite
  27.   engine.
  28. DirtyRect-
  29.   Returns the sprite's dirty rectangle ... a union of its
  30.   current and previous positions.  Used by the sprite
  31.   engine.
  32. Height-
  33.   The height of the sprite, in pixels.  Descendant classes
  34.   MUST assign a value to this property.
  35. MarginLeft, MarginRight, MarginTop, MarginBottom-
  36.   Decreases the bounding rectangle for this sprite for collision
  37.   detection purposes.
  38. MotionType-
  39.   Controls whether the sprite continues in a straight line after
  40.   it reaches its destination or whether it stops.
  41. Moved-
  42.   Flags whether the sprite moved during the last cycle.  Used
  43.   by the sprite engine.
  44. PhysicalPosition-
  45.   The physical position of the sprite in the DIBDrawingSurface,
  46.   after taking Offset values into account.
  47. Position-
  48.   The logical position of the sprite in the DIBDrawingSurface
  49.   coordinates.
  50. Priority-
  51.   The ZOrder of the sprite.  Sprites with a lower value will
  52.   appear on top.  Use the ChangeSpritePriority method of
  53.   TSpriteEngine to change a sprite's priority, instead of changing
  54.   this property directly.
  55. Speed-
  56.   The speed of the sprite.  The lower the number, the faster
  57.   the sprite.
  58. Tag-
  59.   Store misc values here.
  60. Visible-
  61.   Controls whether the sprite will be rendered by the engine.
  62. Width-
  63.   The width of the sprite, in pixels.  Descendant classes
  64.   MUST assign a value to this property.
  65.  
  66. Events
  67.  
  68. Methods
  69.  
  70. FudgedDistance-
  71.   Returns the absoulte difference in logical coords between
  72.   this and another sprite.  More economical than calling the
  73.   standard distance formula, but not as accurate.  Can be
  74.   useful for collision detection.
  75. Move-
  76.   You can override this procedure to augment or replace
  77.   the default sprite movement routines.
  78. RefreshBackground-
  79.   This method is called by the sprite engine and is part
  80.   of the dirty rectangle system.
  81. Render-
  82.   This method MUST be overriden to provide an implementation
  83.   for the sprite's rendering on the DIBDrawingSurface.
  84. *********************************************)
  85.  
  86. interface
  87.  
  88. uses
  89.   Windows, SysUtils, Classes, Graphics, Controls, DIBDrawingSurface,
  90.   Utility;
  91.  
  92. type
  93.  
  94.   TMotionType = ( mtStopAtDest, mtContinuous );
  95.  
  96.   TSprite = class( TObject )
  97.   private
  98.      FMoved: boolean;
  99.      nCycle: word;
  100.      nDX, nDY: integer;
  101.      nIncX, nIncY: integer;
  102.      nError: integer;
  103.      nInc: byte;
  104.      FPri: integer;
  105.      FMotion: TMotionType;
  106.      FVisible: boolean;
  107.      FDirty: boolean;
  108.      FSetMoved: boolean;
  109.      FWidth: integer;
  110.      FHeight: integer;
  111.      FWidth2: integer;
  112.      FHeight2: integer;
  113.      FTag: integer;
  114.      bKill: boolean;
  115.      FMarginLeft, FMarginRight, FMarginTop, FMarginBottom: integer;
  116.   protected
  117.      dds: TDIBDrawingSurface;
  118.      ptDestination: TPoint;
  119.      nSpeed: byte;
  120.      ptLastPosition: TPoint;    { Used to refresh the background in dirty rectangle system }
  121.      ptLastDrawn: TPoint;       { The last position the sprite was drawn }
  122.      ptPosition: TPoint;        { Current logical position }
  123.      ptPhysical: TPoint;        { Logical location - offsets }
  124.      function GetBoundingRect: TRect;
  125.      function GetDirtyRect: TRect;
  126.      procedure SetDestination( const pt: TPoint );
  127.      procedure SetSpeed( const n: byte );
  128.      procedure SetWidth( n: integer );
  129.      procedure SetHeight( n: integer );
  130.      procedure SetDead( b: boolean );
  131.   public
  132.      engine: TComponent;        { The sprite engine that this sprite is registered with }
  133.      constructor Create;
  134.      function FudgedDistance( s: TSprite ): word;
  135.      procedure Move; dynamic;
  136.      procedure PreMove; dynamic;
  137.      procedure PostMove; dynamic;
  138.      procedure RefreshBackground; dynamic;
  139.      procedure Render; dynamic;
  140.      property BoundingRect: TRect read GetBoundingRect;
  141.      property Destination: TPoint read ptDestination write SetDestination;
  142.      property Dead: boolean read bKill write SetDead;
  143.      property DIBDrawingSurface: TDIBDrawingSurface read dds write dds;
  144.      property Dirty: boolean read FDirty write FDirty;
  145.      property DirtyRect: TRect read GetDirtyRect;
  146.      property Height: integer read FHeight write SetHeight;
  147.      property MarginLeft: integer read FMarginLeft write FMarginLeft;
  148.      property MarginRight: integer read FMarginRight write FMarginRight;
  149.      property MarginTop: integer read FMarginTop write FMarginTop;
  150.      property MarginBottom: integer read FMarginBottom write FMarginBottom;
  151.      property MotionType: TMotionType read FMotion write FMotion;
  152.      property Moved: boolean read FMoved write FSetMoved;
  153.      property PhysicalPosition: TPoint read ptPhysical;
  154.      property Position: TPoint read ptPosition write ptPosition;
  155.      property Priority: integer read FPri write FPri;
  156.      property Speed: byte read nSpeed write SetSpeed;
  157.      property Tag: integer read FTag write FTag;
  158.      property Visible: boolean read FVisible write FVisible default TRUE;
  159.      property Width: integer read FWidth write SetWidth;
  160.   end;
  161.  
  162. implementation
  163.  
  164. uses
  165.   SpriteEngine;
  166.  
  167. constructor TSprite.Create;
  168. begin
  169.   dds := nil;
  170.   Priority := 1;
  171.   ptPosition := Point( 0, 0 );
  172.   SetSpeed( 20 );
  173.   SetDestination( Point( 0, 0 ) );
  174.   MotionType := mtStopAtDest;
  175.   FVisible := TRUE;
  176. end;
  177.  
  178. procedure TSprite.PreMove;
  179. begin
  180.   FDirty := FALSE;
  181.  
  182. { Handle wrapping if it's enabled }
  183.   if dds.WrapHorizontal then
  184.      begin
  185.         if ptPosition.X < 0 then
  186.            ptPosition.X := dds.PhysicalWidth;
  187.         if ptPosition.X > dds.PhysicalWidth then
  188.            ptPosition.X := 0;
  189.      end;
  190.   if dds.WrapVertical then
  191.      begin
  192.         if ptPosition.Y < 0 then
  193.            ptPosition.Y := dds.PhysicalHeight;
  194.         if ptPosition.Y > dds.PhysicalHeight then
  195.            ptPosition.Y := 0;
  196.      end;
  197.  
  198. { Adjust physical position based on offset into logical space }
  199.   ptPhysical := ptPosition;
  200.   Dec( ptPhysical.X, dds.OffsetX );
  201.   Dec( ptPhysical.Y, dds.OffsetY );
  202. end;
  203.  
  204. (***************************************************
  205. The default Move method will move the sprite toward
  206. it's destination at a constant speed.
  207. ***************************************************)
  208. procedure TSprite.Move;
  209. var
  210.   bMoveX, bMoveY: boolean;
  211. begin
  212.  
  213.   bMoveX := TRUE;
  214.   bMoveY := TRUE;
  215.  
  216. { Check to see if sprite has reached its destination }
  217.   if FMotion = mtStopAtDest then
  218.      begin
  219.         if nIncX > 0 then
  220.            begin
  221.               if ptPosition.X >= ptDestination.X then
  222.                  bMoveX := FALSE;
  223.            end
  224.         else
  225.            begin
  226.               if ptPosition.X <= ptDestination.X then
  227.                  bMoveX := FALSE;
  228.            end;
  229.         if nIncY > 0 then
  230.            begin
  231.               if ptPosition.Y >= ptDestination.Y then
  232.                  bMoveY := FALSE;
  233.            end
  234.         else
  235.            begin
  236.               if ptPosition.Y <= ptDestination.Y then
  237.                  bMoveY := FALSE;
  238.            end;
  239.      end;
  240.  
  241.   if bMoveX or bMoveY then
  242.      begin
  243.         Inc( nCycle );
  244.         if nCycle >= nSpeed then
  245.            begin
  246.               nCycle := 0;
  247.               if nDX > nDY then
  248.                  begin
  249.                     Inc( nError, nDY );
  250.                     if nError > nDX then
  251.                        begin
  252.                           Dec( nError, nDX );
  253.                           if bMoveY then
  254.                              Inc( ptPosition.Y, nIncY );
  255.                        end;
  256.                     if bMoveX then
  257.                        Inc( ptPosition.X, nIncX );
  258.                  end
  259.               else
  260.                  begin
  261.                     Inc( nError, nDX );
  262.                     if nError > 0 then
  263.                        begin
  264.                           Dec( nError, nDY );
  265.                           if bMoveX then
  266.                              Inc( ptPosition.X, nIncX );
  267.                        end;
  268.                     if bMoveY then
  269.                        Inc( ptPosition.Y, nIncY );
  270.                  end;
  271.            end;
  272.      end
  273.   else
  274.      ptPosition := ptDestination;
  275.  
  276. end;
  277.  
  278. procedure TSprite.PostMove;
  279. begin
  280.   FMoved := not EqualPt( ptPosition, ptLastDrawn ) or FSetMoved;
  281.   ptLastPosition := ptPosition;
  282.   FSetMoved := FALSE;
  283. end;
  284.  
  285. (***************************************************
  286. Determine the sprite's speed vector's when its
  287. destination changes.
  288. ***************************************************)
  289. procedure TSprite.SetDestination( const pt: TPoint );
  290. begin
  291.   nError := 0;
  292.   ptDestination := pt;
  293.   nDX := ptDestination.X - ptPosition.X;
  294.   nDY := ptDestination.Y - ptPosition.Y;
  295.   if nDX >= 0 then
  296.      nIncX := nInc
  297.   else
  298.      begin
  299.         nIncX := -nInc;
  300.         nDX := -nDX;
  301.      end;
  302.   if nDY >= 0 then
  303.      nIncY := nInc
  304.   else
  305.      begin
  306.         nIncY := -nInc;
  307.         nDY := -nDY;
  308.      end;
  309. end;
  310.  
  311. (***************************************************
  312. The speed will determine how many pixels per turn the
  313. sprite moves, or how many cycles of delay are introduced
  314. between movement.
  315. ***************************************************)
  316. procedure TSprite.SetSpeed( const n: byte );
  317. begin
  318.   nSpeed := 0;
  319.   if n <= 10 then
  320.      nInc := 11 - n
  321.   else
  322.      begin
  323.         nInc := 1;
  324.         nSpeed := n - 11;
  325.      end;
  326.   SetDestination( ptDestination );
  327. end;
  328.  
  329. (*********************************************
  330. Determine a "fudged" distance by simply adding
  331. the absolute values of the positions.  Faster
  332. than executing the correct distance formula.
  333. *********************************************)
  334. function TSprite.FudgedDistance( s: TSprite ): word;
  335. begin
  336.   Result := Abs( ptPosition.X - s.ptPosition.X ) + Abs( ptPosition.Y - s.ptPosition.Y );
  337. end;
  338.  
  339. procedure TSprite.Render;
  340. begin
  341.   ptLastDrawn := ptPhysical;
  342. end;
  343.  
  344. (***************************************************
  345. Returns the union of the sprite's current rectangle
  346. and the rectangle of its last position.  Used by the
  347. sprite engine when dirty rectangle processing is on.
  348. ***************************************************)
  349. function TSprite.GetDirtyRect: TRect;
  350. var
  351.   rectOld, rectNew, rectUnion: TRect;
  352. begin
  353.   rectOld := Rect( ptLastDrawn.X - FWidth2,
  354.      ptLastDrawn.Y - FHeight2,
  355.      ptLastDrawn.X + FWidth2,
  356.      ptLastDrawn.Y + FHeight2 );
  357.  
  358.   rectNew := Rect( ptPhysical.X - FWidth2,
  359.      ptPhysical.Y - FHeight2,
  360.      ptPhysical.X + FWidth2,
  361.      ptPhysical.Y + FHeight2 );
  362.  
  363.   UnionRect( rectUnion, rectOld, rectNew );
  364.   Result := rectUnion;
  365. end;
  366.  
  367. (***************************************************
  368. Restores the area of the sprite's last position.
  369. Called by the sprite engine.
  370. ***************************************************)
  371. procedure TSprite.RefreshBackground;
  372. var
  373.   rectDest: TRect;
  374. begin
  375.   if Visible then
  376.      begin
  377.         rectDest := Rect( ptLastDrawn.X - FWidth2,
  378.            ptLastDrawn.Y - FHeight2,
  379.            ptLastDrawn.X + FWidth2 - 1,
  380.            ptLastDrawn.Y + FHeight2 - 1 );
  381.         if Assigned( dds.BackgroundDIB ) then
  382.            dds.DIBCanvas.CopyRect( rectDest, dds.BackgroundDIB.DIBCanvas, rectDest )
  383.         else
  384.            begin
  385.               dds.DIBCanvas.BrushColorIndex := dds.AutoBlankColor;
  386.               dds.DIBCanvas.FillRect( rectDest );
  387.            end;
  388.      end;
  389. end;
  390.  
  391. (***************************************************
  392. The sprite's width and height (as well as half of the
  393. sprite's width and height) are stored.
  394. ***************************************************)
  395. procedure TSprite.SetWidth( n: integer );
  396. begin
  397.   FWidth := n;
  398.   FWidth2 := n div 2;
  399. end;
  400.  
  401. procedure TSprite.SetHeight( n: integer );
  402. begin
  403.   FHeight := n;
  404.   FHeight2 := n div 2;
  405. end;
  406.  
  407. (***************************************************
  408. Return the sprite's bounding rect for collision
  409. detection.  Here the sprite's four margins are taken
  410. into account, as well as size.
  411. ***************************************************)
  412. function TSprite.GetBoundingRect: TRect;
  413. begin
  414.   Result := Rect( ptPhysical.X - FWidth2 + FMarginLeft,
  415.      ptPhysical.Y - FHeight2 + FMarginTop,
  416.      ptPhysical.X + FWidth2 + 1 - FMarginRight,
  417.      ptPhysical.Y + FHeight2 + 1 - FMarginBottom );
  418. end;
  419.  
  420. procedure TSprite.SetDead( b: boolean );
  421. begin
  422.   if b <> bKill then
  423.      begin
  424.         bKill := b;
  425.         if b then
  426.            if engine <> nil then
  427.               TSpriteEngine( engine ).RemoveSprite( self );
  428.      end;
  429. end;
  430.  
  431. end.
  432.